﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Manager;
using SdmxMl.Common;
using SdmxMl.Structure;

namespace SdmxMl.Panels
{
    public partial class DlgSetMap : Form
    {
        private StrSetMapItemList mapList;

        public DlgSetMap(StrSetMapItemList mil)
        {
            InitializeComponent();
            mapList = mil;
        }

        /// <summary>
        /// At start, fill tree with artefact item collection
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void DlgSetMap_Load(object sender, EventArgs e)
        {
            Artefact arSource = null;
            Artefact arTarget = null;
            SmManager sm = ReferenceManager.GetSmContainerImage();

            if (mapList.SourceRef.IsFilled)
                arSource = sm.GetArtefact(mapList.ArtType, mapList.SourceRef, true);
            if (mapList.TargetRef.IsFilled)
                arTarget = sm.GetArtefact(mapList.ArtType, mapList.TargetRef, true);

            if (arSource == null || arTarget == null)
            {
                MessageBox.Show(this, "Referenced artefact(s) cannot be loaded", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
            }

            FillTreeView(treeViewLeft, arSource);
            FillTreeView(treeViewRight, arTarget);
        }

        /// <summary> Fills treeview with corresponding artefact items/ </summary>
        /// <param name="tv">Treeview component to fill</param>
        /// <param name="a">artefact owning items</param>
        private void FillTreeView(TreeView tv, Artefact a)
        {
            tv.BeginUpdate();
            tv.Nodes.Clear();
            if (a != null)
            {
                TreeNode root = new TreeNode();
                a.FillNode(root);
                tv.Nodes.Add(root.Nodes[0].Nodes[0]);
                tv.ExpandAll();
            }
            tv.EndUpdate();
        }
       
        /// <summary> Ensures two treeviews with same width </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void panelFlow_Resize(object sender, EventArgs e)
        {
            int middle = this.panelMiddle.Width;
            int width = (this.Width / 2) - middle / 2;
            this.panelLeft.Width = width;
            this.panelRight.Width = width;
        }

        /// <summary>
        /// Reflects tree item in corresponding edit box (source or target)
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void TreeAfterSelect(object sender, TreeViewEventArgs e)
        {
            TreeView tv = sender as TreeView;
            if (tv != null && e.Node != tv.Nodes[0])
            {
                ISdmxHierarchyListItem item = e.Node.Tag as ISdmxHierarchyListItem;
                if (tv == treeViewLeft && item != null)
                    NumTextSource.Text = item.Id;
                else if (tv == treeViewRight && item != null)
                    numTextTarget.Text = item.Id;
            }
        }

        /// <summary>
        /// Apply value mapping to map list, check if not already existing
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void buttonApply_Click(object sender, EventArgs e)
        {
            string source = NumTextSource.Text.Trim();
            string target = numTextTarget.Text.Trim();
            if (source.Length == 0 || target.Length == 0)
                MessageBox.Show(this, "Please fill source and target values", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
            {
                // Check that source & target are defined in tree
                TreeNode targetNode = null;
                LocateValue(treeViewLeft.Nodes[0], source, ref targetNode);
                if (targetNode != null)
                {
                    targetNode = null;
                    LocateValue(treeViewRight.Nodes[0], target, ref targetNode);
                    if (targetNode != null)
                    {
                        // Check if already defined
                        StrSetMapItem item = new StrSetMapItem(source, target, numTextBoxAlias.Text.Trim());
                        if (mapList.IsDefined(item))
                            MessageBox.Show(this, "Correspondance is already defined: "+ item.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        else
                        {
                            mapList.Add(item);
                            numTextBoxAlias.Text = NumTextSource.Text = numTextTarget.Text = string.Empty;
                        }
                    }
                    else
                    {
                        MessageBox.Show(this, "Target value is not part of list", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else
                {
                    MessageBox.Show(this, "Source value is not part of list", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            // reset for next selection
            treeViewLeft.SelectedNode = null;
            treeViewRight.SelectedNode = null;
        }

        /// <summary>
        /// Recurse to locate a tree item matching value specified in edit box (source or target)
        /// </summary>
        /// <param name="node">node to start with</param>
        /// <param name="val">value to look for (as id)</param>
        /// <param name="targetNode">reference to set matching node</param>
        public void LocateValue(TreeNode node, string val, ref TreeNode targetNode)
        {
            ISdmxHierarchyListItem item = node.Tag as ISdmxHierarchyListItem;
            if (item != null && item.Id == val)
                targetNode = node;
            else
            {
                foreach (TreeNode n in node.Nodes)
                {
                    if (targetNode == null)
                        LocateValue(n, val, ref targetNode);
                }
            }

        }
    }
}
